/*
 * BlockWorld.java
 *
 * Created on Jun 1, 2011, 4:19:59 AM
 */
package desktopstrips;

import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayDeque;
import java.util.Iterator;
import strips.*;
/**
 *
 * @author mire
 */
public class BlockWorld extends JPanel {

    class ColoredBlock extends Block{
        private Color color;

        public ColoredBlock(Block b, Color color) {
            super(b);
            this.color = color;
        }

        public ColoredBlock(Block b) {
            super(b);
        }

        public Color getColor() {
            return color;
        }

        public void setColor(Color color) {
            this.color = color;
        }
        
    }
    
    private static final int blockSize          = 100;
    private static final int blocksOnTable      = 7;
    private static final int blocksTower        = 4;
    private ArrayDeque<Predicate> currentState;
    private ColoredBlock[][] grid;
    
    /** Creates new form BlockWorld */
    public BlockWorld() {
        currentState = new ArrayDeque<Predicate>();
        initComponents();

    }
    
    public void setCurrentState(ArrayDeque<Predicate> currentState) {
        this.currentState = currentState;
    }

    public ArrayDeque<Predicate> getCurrentState() {
        return currentState;
    }
    
    public void clearGrid()
    {
        grid = new ColoredBlock[blocksOnTable][blocksTower];
    }
    
    private void paintBlock(Graphics g, ColoredBlock cb, int positionX, int positionY)
    {   
        Graphics2D g2 = (Graphics2D) g;
        
        g2.setColor(cb.getColor());
        g2.fillRect(positionX, positionY, blockSize, blockSize);
        
        g2.setColor(Color.BLUE);
        g2.drawRect(positionX, positionY, blockSize, blockSize);
        
        g2.setColor(cb.getColor()==Color.WHITE?Color.DARK_GRAY:Color.LIGHT_GRAY);
        String name = cb.getName();
        int nameWidth = g2.getFontMetrics().stringWidth(name);
        g2.drawString(name, positionX + blockSize/2 - nameWidth/2, positionY + blockSize/2);
    }
    
    private void paintArm(Graphics g)
    {
        Graphics2D g2 = (Graphics2D) g;
        
        int globalWidth = this.getWidth();
        
        g2.setColor(new Color(0,0,128));  //Navy Blue
        g2.fillRect((int)(globalWidth/2 - 2.5D), 0, 5, 25);
        g2.fillRect((int)(globalWidth/2 - blockSize/2 - 5.5D), 25, 5, 25);
        g2.fillRect((int)(globalWidth/2 + blockSize/2 + 2.5D), 25, 5, 25);
        g2.fillRect((int)(globalWidth/2 - blockSize/2 - 2.5D), 25, blockSize + 10, 5);
        
    }
    
    private void paintTable(Graphics g)
    {
        Graphics2D g2 = (Graphics2D) g;
        
        int globalHeight = this.getHeight();
        int globalWidth = this.getWidth();
        
        int tableLenght = blocksOnTable*blockSize;
        int tableStartX = (int) (globalWidth/2 - tableLenght/2.);
        
        
        g2.setColor(new Color(139,69,19)); //Brown
        g2.fillRect((int)(tableStartX + blockSize - 2.5D), globalHeight - 30, 5, 30);
        g2.fillRect((int)(tableStartX + tableLenght - blockSize - 2.5D), globalHeight - 30, 5, 30);
        g2.fillRect(tableStartX, globalHeight - 35, tableLenght, 5);
    }
    

    private void paintCurrentState(Graphics g) {
        ArrayDeque<Predicate> tempState = currentState;
        ArrayDeque<Block> blocks = StateParser.parseAtributesInLine(currentState.toString());
        boolean[][] paintGrid = new boolean[blocksOnTable][blocksTower];

        int globalHeight = this.getHeight();
        int globalWidth = this.getWidth();
        int tableLenght = blocksOnTable * blockSize;

        int blockPositionX = (int) (globalWidth / 2 - tableLenght / 2.);
        int blockPositionY = globalHeight - 35 - blockSize;
        Iterator<Predicate> it = tempState.iterator();
        int blocksNum = 0;
        while (it.hasNext() && !blocks.isEmpty() && blocksNum < blocksOnTable) {
            Predicate element = it.next();
            Block b = element.getAtributes().peek();

            if (element.getName().equals(Goal.onTable)) {
                Color c = currentState.contains(new Predicate(Goal.black, element.getAtributes())) ? Color.BLACK : Color.WHITE;

                for (int i = blocksNum; i < blocksOnTable; i++) {
                    if (grid[i][0] != null && grid[i][0].getName().equals(b.getName())) {
                        if (grid[i][0].getColor() != c) {
                            grid[i][0].setColor(c);
                        }
                        paintGrid[i][0] = true;
                        blocks.remove(b);
                        break;
                    }
                }
               if(!blocks.contains(b))
                   continue;

                while (grid[blocksNum][0] != null) {
                    blocksNum++;
                }
                grid[blocksNum][0] = new ColoredBlock(b, c);
                paintGrid[blocksNum][0] = true;
                blocks.remove(b);
                blocksNum++;
                continue;
            }

            if (element.getName().equals(Goal.holding)) {
                Color c = currentState.contains(new Predicate(Goal.black, element.getAtributes())) ? Color.BLACK : Color.WHITE;
                blocks.remove(b);
                int armX = (int) (globalWidth / 2. - blockSize / 2.);
                paintBlock(g, new ColoredBlock(b, c), armX, 30);
            }
        }
        if (blocksNum > blocksOnTable) {
            System.out.println("Nedovoljno veliki sto");
            return;
        }

        for (int level = 1; !blocks.isEmpty(); level++) {
            it = tempState.iterator();
            while (it.hasNext()) {
                Predicate element = it.next();
                if (element.getName().equals(Goal.on)) {
                    Block first = element.getAtributes().peekFirst();
                    Block second = element.getAtributes().peekLast();

                    for (int i = 0; i < blocksOnTable; i++) {
                        if (grid[i][level - 1] != null && second.getName().equals(grid[i][level - 1].getName())) {


                            ArrayDeque<Block> ab = new ArrayDeque<Block>();
                            ab.add(first);
                            Color c = currentState.contains(new Predicate(Goal.black, ab)) ? Color.BLACK : Color.WHITE;

                            if (grid[i][level] != null && grid[i][level].getName().equals(first.getName())) {
                                if (grid[i][level].getColor() != c) {
                                    grid[i][level].setColor(c);
                                }
                            } else {
                                grid[i][level] = new ColoredBlock(first, c);
                            }

                            paintGrid[i][level] = true;
                            blocks.remove(first);
                            break;
                        }
                    }
                }
            }
        }
        
        for(int i=0; i<blocksOnTable; i++)
            for(int j=0; j<blocksTower; j++)
                if(paintGrid[i][j]){
                    paintBlock(g, grid[i][j], blockPositionX + i * blockSize, blockPositionY - j * blockSize);
                } else {
                    grid[i][j] = null;
                }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        
        paintTable(g);
        paintArm(g);
        
        if(!currentState.isEmpty())
            paintCurrentState(g);
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}
